<!doctype html>
<html lang="en">
<head>
  <title>WebGL Demo</title>
  <meta charset="utf-8">
  <style>
    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
    }
  </style>
</head>

<body>
<canvas id="glcanvas" width="640" height="480"></canvas>
<div id="uiContainer">
  <div id="ui">
    <div id="fRotation"></div>
  </div>
</div>
</body>

<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-lessons-ui.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>

<script  id="vertex-shader-3d" type="x-shader/x-vertex">
  attribute vec4 a_position;
varying vec4 v_position;
void main() {
  v_position = a_position;
  gl_Position = a_position;
  gl_Position.z = 1.0;
}
</script>
<!-- fragment shader -->
<script  id="fragment-shader-3d" type="x-shader/x-fragment">
precision mediump float;

uniform samplerCube u_skybox;
uniform mat4 u_viewDirectionProjectionInverse;

varying vec4 v_position;
void main() {
  vec4 t = u_viewDirectionProjectionInverse * v_position;
  gl_FragColor = textureCube(u_skybox, normalize(t.xyz / t.w));
  }
</script>

<script>
  main();

  function main() {
    var canvas = document.querySelector("#glcanvas");
    var gl = canvas.getContext("webgl");
    if (!gl) {
      return;
    }

    var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);
    //找到刚刚创建的程序属性位置
    var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
    var skyboxLocation = gl.getUniformLocation(program, "u_skybox");
    var viewDirectionProjectionInverseLocation = gl.getUniformLocation(program, "u_viewDirectionProjectionInverse");


    //创建缓冲区
    var positionBuffer = gl.createBuffer();

    //绑定缓冲区
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

    //通过绑定点应用缓冲区中的数据
    setGeometry(gl);

    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);

    const faceInfos = [
      {
        target: gl.TEXTURE_CUBE_MAP_POSITIVE_X,
        url: 'https://webglfundamentals.org/webgl/resources/images/computer-history-museum/pos-x.jpg',
      },
      {
        target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
        url: 'https://webglfundamentals.org/webgl/resources/images/computer-history-museum/neg-x.jpg',
      },
      {
        target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
        url: 'https://webglfundamentals.org/webgl/resources/images/computer-history-museum/pos-y.jpg',
      },
      {
        target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
        url: 'https://webglfundamentals.org/webgl/resources/images/computer-history-museum/neg-y.jpg',
      },
      {
        target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
        url: 'https://webglfundamentals.org/webgl/resources/images/computer-history-museum/pos-z.jpg',
      },
      {
        target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
        url: 'https://webglfundamentals.org/webgl/resources/images/computer-history-museum/neg-z.jpg',
      },
    ];

    faceInfos.forEach((faceInfo) => {
      const {target, url} = faceInfo;
      console.log(faceInfo)
      // Upload the canvas to the cubemap face.
      const level = 0;
      const internalFormat = gl.RGBA;
      const width = 512;
      const height = 512;
      const format = gl.RGBA;
      const type = gl.UNSIGNED_BYTE;

      gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, null);

      const image = new Image();
      image.crossOrigin = "Anonymous"
      image.src = url;
      image.addEventListener('load', function() {
        // Now that the image has loaded make copy it to the texture.
        gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
        gl.texImage2D(target, level, internalFormat, format, type, image);
        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
      });
    });

    gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);

    function radToDeg(r) {
      return r * 180 / Math.PI;
    }

    function degToRad(d) {
      return d * Math.PI / 180;
    }

    var fieldOfViewRadians = degToRad(60);

    requestAnimationFrame(drawScene);

    function drawScene(time){

      time *= 0.001;
      webglUtils.resizeCanvasToDisplaySize(gl.canvas);

      //转换gl_Positon返回像素，称为屏幕空间。可用把gl.viewport把画布的当前大小传递给它
      gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

      //把画布清理干净
      gl.clearColor(0, 0, 0, 1);
      gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
      gl.enable(gl.CULL_FACE);
      gl.enable(gl.DEPTH_TEST);

      //告诉webgl要执行那个着色器程序
      gl.useProgram(program);

      //告诉webgl如何从上面设置的缓冲区中获取数据，并将其提供给着色器中的属性
      gl.enableVertexAttribArray(positionAttributeLocation);

      //绑定位置缓冲区。
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

      // 告诉属性如何从位置缓冲区获取数据(数组_缓冲器)
      var size = 2;          // 每次迭代2个组件
      var type = gl.FLOAT;   // 数据为32位浮点数。
      var normalize = false; // 不要标准化数据
      var stride = 0;        // 0=向前移动，大小*每次迭代的大小(类型)，以获得下一个位置
      var offset = 0;        // 从缓冲区的开头开始
      gl.vertexAttribPointer(
        positionAttributeLocation, size, type, normalize, stride, offset)


      var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
      var projectionMatrix =
        m4.perspective(fieldOfViewRadians, aspect, 1, 2000);
      // camera going in circle 2 units from origin looking at origin
      var cameraPosition = [Math.cos(time * .1), 0, Math.sin(time * .1)];
      var target = [0, 0, 0];
      var up = [0, 1, 0];
      // Compute the camera's matrix using look at.
      var cameraMatrix = m4.lookAt(cameraPosition, target, up);

      // Make a view matrix from the camera matrix.
      var viewMatrix = m4.inverse(cameraMatrix);

      // We only care about direciton so remove the translation
      viewMatrix[12] = 0;
      viewMatrix[13] = 0;
      viewMatrix[14] = 0;

      var viewDirectionProjectionMatrix =
        m4.multiply(projectionMatrix, viewMatrix);
      var viewDirectionProjectionInverseMatrix =
        m4.inverse(viewDirectionProjectionMatrix);

      // Set the uniforms
      gl.uniformMatrix4fv(
        viewDirectionProjectionInverseLocation, false,
        viewDirectionProjectionInverseMatrix);

      // Tell the shader to use texture unit 0 for u_skybox
      gl.uniform1i(skyboxLocation, 0);

      // let our quad pass the depth test at 1.0
      gl.depthFunc(gl.LEQUAL);



      var primitiveType = gl.TRIANGLES;
      var offset = 0;
      var count = 6*1;
      gl.drawArrays(primitiveType, offset, count);

      requestAnimationFrame(drawScene);
    }

  }

  function setGeometry(gl) {
    var positions = new Float32Array(
      [
        -1, -1,
        1, -1,
        -1,  1,
        -1,  1,
        1, -1,
        1,  1,
      ]);
    gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
  }


</script>
</html>

